package text.adventure.blackboard;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Iterator;

import text.adventure.data.TextCommand;

public class Blackboard {
	private List<Observer> notifyList;
	private List<Observer> questionList;
	private Queue<Observer> subscriptions;
	private Queue<Boolean> sub_mode;
	private Observer genericResponse;
	private boolean sending;
	private boolean asking;
	private static boolean hasInstance;
	private static Blackboard instance;
	
	private Blackboard() {
		notifyList = new ArrayList<Observer>();
		questionList = new ArrayList<Observer>();
		subscriptions = new LinkedList<Observer>();
		sub_mode = new LinkedList<Boolean>();
		sending = false;
		asking = false;
		hasInstance = false;
	}
	
	public void subscribe(Observer obs) {
		subscriptions.add(obs);
		sub_mode.add(true);
		update();
	}
	
	public void unsubscribe(Observer obs) {
		subscriptions.add(obs);
		sub_mode.add(false);
	}
	
	public int getFlag(String flagname, int expected) {
		asking = true;
		Iterator<Observer> obslist = questionList.iterator();
		int answer = getFlag_(flagname, expected, obslist);
		asking = false;
		update();
		return answer;
	}
	private int getFlag_(String flagname, int status, Iterator<Observer> obslist) {
		if(obslist.hasNext()) {
			int next_status = obslist.next().getFlag(flagname, status);
			return getFlag_(flagname, next_status, obslist);
		} else {
			return status;
		}
	}
	
	public boolean receive(TextCommand textc) {
		sending = true;
		Iterator<Observer> obslist = notifyList.iterator();
		boolean response = receive_(textc, false, obslist);
		sending = false;
		if(!response) {
			genericResponse.receive(textc);
		}
		update();
		return response;
	}
	private boolean receive_(TextCommand textc, boolean status, Iterator<Observer> obslist) {
		if(obslist.hasNext()) {
			if(status) {
				obslist.next().receive(textc);
				return receive_(textc, true, obslist);
			} else {
				boolean next_status = obslist.next().receive(textc);
				return receive_(textc, next_status, obslist);
			}
		} else { 
			return status;
		}
	}
	
	private void update() {
		if(!sending && !asking && !subscriptions.isEmpty()) {
			if(sub_mode.poll()) {
				notifyList.add(subscriptions.poll());
				questionList.add(subscriptions.poll());
			} else {
				notifyList.remove(subscriptions.poll());
				questionList.remove(subscriptions.poll());
			}
		}
	}
	
	public static Blackboard getInstance() { // = gebe Handle aufs Blackboard
		if(Blackboard.hasInstance) {
			return Blackboard.instance;
		} else {
			Blackboard.instance = new Blackboard();
			Blackboard.hasInstance = true;
			return Blackboard.instance;
		}
	}
}